package org.example.springbook.controller;

import lombok.extern.slf4j.Slf4j;
import org.example.springbook.dao.BookDao;
import org.example.springbook.enums.ResultCode;
import org.example.springbook.model.*;
import org.example.springbook.service.BookService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import static org.example.springbook.constants.Constant.SESSION_USER_KEY;

@Slf4j
@RestController
@RequestMapping("/book")
public class BookController {

    private static final Logger log = LoggerFactory.getLogger(BookController.class);
    @Autowired
    private BookService bookService;
    /*@RequestMapping("/getBookList")
    public List<BookInfo> getBookList() {
        //1. 获取图书数据
        //2. 对图书数据进行处理, 因为图书的状态在数据库中存的是0, 1
        //我们就规定由后端来告诉前端图书0,1 所代表的状态
        //3 .返回数据


        List<BookInfo> bookInfos = bookService.getBookList();
        //那么这个对图书数据的处理代码就要移动到service层了
        *//*for (BookInfo bookInfo : bookInfos) {
            if (bookInfo.getStatus()==1){
                bookInfo.setStatusCN("可借阅");
            }else {
                bookInfo.setStatusCN("不可借阅");
            }
        }*//*
        return bookInfos;
    }*/
    /*// 需要应用分层 要不然就显得代码太乱了
    // 所以这个数据部分就移动到数据层dao了
    private List<BookInfo> mockData() {
        List<BookInfo> bookInfos = new ArrayList<BookInfo>();
        for (int i = 0; i < 15; i++) {
            BookInfo bookInfo = new BookInfo();
            bookInfo.setId(i);
            bookInfo.setBookName("图书"+i);
            bookInfo.setAuthor("作者"+i);
            bookInfo.setCount(new Random().nextInt(200));
            bookInfo.setPrice(new BigDecimal(new Random().nextInt(100)));
            bookInfo.setPublish("出版社"+i);
            bookInfo.setStatus(i%5==0?2:1);
            bookInfos.add(bookInfo);
        }
        return bookInfos;
    }*/

    // 图书列表接口
    // 后端需要返回的结果是 当前页的内容 records 是一个List
    // 还需要返回的是总条数, 以便于前端进行展示
    // 那么这个时候 上面获取图书列表的返回值就不适用了
    // 我们可以将上述两个属性封装在对象中 要创建一个PageResult对象
    // 以后返回后端返回的结果也尽量放在一个对象中


    // 我们在学习阶段 参数最好还是写在对象中 这是因为后期好扩展
    // 要不然 前端后期要有多传参数的需求 那么我们的接口方法也就要更改
    // 成本就太大了
    // 所以将currentPage pageSize 放到一个对象当中
    // 这样的的话 参数就可以使用一个对象了
    @RequestMapping("/getBookListByPge")
    // 规定好返回结果后, 那我们来拿翻页列表来进行登录校验
    // 那么我们的返回值就要改成Result了
    // 那么原来的返回值就都要改了
    //public PageResult<BookInfo> getBookListByPge(PageRequest pageRequest) {
    public Result getBookListByPge(PageRequest pageRequest, HttpSession session) {
        // 那我们这里一开始的动作就是 是否登录校验了 如何进行校验呢 要从Session里面拿值
        // Session在哪呢? 我们当时在UserController里面存了Session 所以从那里拿
        // 但是这里我们又发现了一个问题 如果某处代码的session_user_key 写错了 或者改变了
        // 那我们其他地方也要进行修改
        // 那么我们就可以将这些容易写错的变量 放到一个常量类中 那就避免了要修改很多处地方的问题
        // 以后要避免将字符串写在代码中 如果一个字符串 只在这个类中使用一次 没有在其他地方使用
        // 那么就可以提到类的上方去
        /*UserInfo userInfo = (UserInfo) session.getAttribute(SESSION_USER_KEY);
        if (userInfo == null || userInfo.getId() <=0 || "".equals(userInfo.getUserName())) {
            // 走到这里表明用户未登录 那我们就返回一个状态码-2
            *//*Result result = new Result();
            result.setCode(ResultCode.UNLOGIN);
            result.setErrMsg("用户未登录");
            result.setData("null");
            return result;*//*
            return Result.unlogin();
        }*/


        // 校验成功

        log.info("查询翻页信息, pageRequest={}", pageRequest);
        // 当我们拿到前端给的参数之后 就可以实现我们的翻页功能了
        // 还是先去写数据库
        // 那么既然要将前端传递过来的参数转化为 我们数据库中的offset和limit(也就是pageSize)
        // 且当你放到了Service中来做 Controller层你拿到的参数又是一个对象
        // 那么bookService中 方法的参数要变为对象 因为你只有一个对象

        //此时Controller这层就来做参数的校验

        if (pageRequest.getPageSize() < 0 || pageRequest.getCurrentPage() < 1) {
            // return null;
            // 有了状态码之后 我们也可以对上面参数校验失败 进行修改
            return Result.fail("参数校验失败");
        }

        // 当我们注入 bookService bookInfoMapper 这些对象时 都可能会发生异常
        // 那们我们就需要捕获异常
        // Controller 和 Service中 都可以写 只写一个也可以
        PageResult<BookInfo> bookInfoPageResult = null;
        try{
            bookInfoPageResult = bookService.selectBookInfoByPage(pageRequest);
            // 可是未登录 登录 内部出错了 这三处的代码就显得冗余重复了
            // 而且这只是一个翻页功能的接口
            // 那如果下面的修改图书 添加图书要用的话
            // 我还是要new Result
            // 所以我们可以提取出来 提到Result里面
            /*Result result = new Result();
            result.setCode(ResultCode.SUCCESS);
            result.setErrMsg("");
            result.setData(bookInfoPageResult);
            return result;*/
            return Result.success(bookInfoPageResult);
        }catch (Exception e){
            log.error("查询翻页信息错误, e:{}", e);
            /*Result result = new Result();
            result.setCode(ResultCode.FAIL);
            result.setErrMsg(e.getMessage());
            result.setData(bookInfoPageResult);
            return result;*/
            return Result.fail(e.getMessage());
        }
        /*// 此时返回类型不匹配 所以要将bookService.selectBookInfoByPage(pageRequest)的返回值改为PageResult
        return bookService.selectBookInfoByPage(pageRequest);*/


        // return bookInfoPageResult;
    }

    @RequestMapping(value = "/addBook", produces = "application/json")
    public String addBook(BookInfo bookInfo) {
        log.info("添加图书, bookInfo={}", bookInfo);
        // Controller层首先要做的就是参数校验
        if (!StringUtils.hasLength(bookInfo.getBookName())
                || !StringUtils.hasLength(bookInfo.getAuthor())
                || bookInfo.getCount()<0
                || bookInfo.getPrice()==null
                || !StringUtils.hasLength(bookInfo.getPublish())){
            return "参数校验失败, 请检查入参";
        }
        Integer result = bookService.addBook(bookInfo);
        if (result <= 0) {
            // 这句代码是我们程序员自己看的
            log.error("添加图书出错, bookInfo={}", bookInfo);
            // 这句代码是返回给用户看的
            return "添加图书出错, 请联系管理员";
        }
        return "";

    }
    @RequestMapping("/queryBookInfoById")
    public BookInfo queryBookInfoById(Integer bookId) {
        log.info("根据图书id查询图书信息, bookId={}", bookId);
        if (bookId <= 0 ) {
            log.error("根据id查询图书失败, bookId={}", bookId);
        }
        BookInfo bookInfo = null;
        try{
            bookInfo = bookService.queryBookInfoById(bookId);
            return bookInfo;
        }catch (Exception e){
            log.error("查询图书信息失败, e:{}", e);
        }
        return null;
    }

    @RequestMapping(value = "/updateBook", produces = "application/json")
    public String updateBook(BookInfo bookInfo) {
        log.info("接收到更新图书的请求, bookInfo={}", bookInfo);
        Integer result = bookService.updateBook(bookInfo);
        if (result <= 0) {
            log.error("更新图书失败, bookInfo={}", bookInfo);
            return "更新图书失败, 请联系管理员";
        }
        return "";
    }


    @RequestMapping(value = "/batchDelete", produces = "application/json")
    // 这里传递集合或者对象参数时 要用@RequestParam这个注解来接收

    public String batchDelete(@RequestParam List<Integer> ids){
        log.info("接收请求, 批量删除图书, 图书ID:{}",ids);
        Integer result = bookService.batchDelete(ids);
        if (result<=0){
            log.error("批量删除失败, ids:{}",ids);
            return "批量删除失败, 请联系管理员";
        }
        return "";
    }
}
